`include"defines.v"
`include"csr_defines.v"

module csr_regfile(

    input  wire                  clk,
	input  wire                  rst,

    input  wire                  ecall_i,
    input  wire                  mret_i,
    input  wire [`RAM_BUS]       pc_i,
    input  wire                  if_reg_valid_i,
    input  wire [`RAM_BUS]       if_pc_i,
    input  wire                  clint_interrupt_i,  //csr_mtime >= csr_mtimecmp;

    input  wire [11:0]           csr_rd_addr,
    input  wire [11:0]           csr_wr_addr,
    input  wire                  csr_rd_ena,
    input  wire                  csr_wr_ena, 
    input  wire [`REG_WIDTH]     csr_wr_data,

    output wire                  clint_o,
    output reg  [`REG_WIDTH]     csr_rd_data,

    output wire [`REG_WIDTH]     mstatus_o,
    output wire [`REG_WIDTH]     mie_o,
    output wire [`REG_WIDTH]     mtvec_o,
    output wire [`REG_WIDTH]     mepc_o,
    output wire [`REG_WIDTH]     mcause_o,
    output wire [`REG_WIDTH]     mtval_o,
    output wire [`REG_WIDTH]     mip_o,
    output wire [`REG_WIDTH]     medeleg_o,
    output wire [`REG_WIDTH]     mideleg_o,
    output wire [`REG_WIDTH]     mscratch_o,

    output wire [`REG_WIDTH]     sstatus_o
  
);
//csr machine  
    reg [62:0]       csr_mstatus; //{sd,csr_mstatus}
    reg [`REG_WIDTH] csr_mie;
    reg [`REG_WIDTH] csr_mtvec;
    reg [`REG_WIDTH] csr_mepc;
    reg [`REG_WIDTH] csr_mcause;
    reg [`REG_WIDTH] csr_mtval;
    reg [`REG_WIDTH] csr_mip;
    reg [`REG_WIDTH] csr_medeleg;
    reg [`REG_WIDTH] csr_mideleg;
    reg [`REG_WIDTH] csr_mscratch;

//csr user 
    reg [`REG_WIDTH] csr_mcycle;
    reg [`REG_WIDTH] csr_minstret;
//clint
    wire clint_interrupt_valid;
    reg  mepc_ready;              // for clint interrupt

//mstatus
    wire       mie, mpie;
    wire [1:0] mpp;
    wire sd;
    assign mie  = csr_mstatus[3];
    assign mpie = csr_mstatus[7];
    assign mpp  = csr_mstatus[12:11]; 
    assign sd   = csr_mstatus[14:13] == 2'b11 | csr_mstatus[16:15] == 2'b11;

    assign mstatus_o    =  {sd,csr_mstatus};
    assign mie_o        =  csr_mie;
    assign mtvec_o      =  csr_mtvec;
    assign mepc_o       =  csr_mepc;
    assign mcause_o     =  csr_mcause;
    assign mtval_o      =  csr_mtval;
    assign mip_o        =  csr_mip;
    assign medeleg_o    =  csr_medeleg;
    assign mideleg_o    =  csr_mideleg;
    assign mscratch_o   =  csr_mscratch;
    assign sstatus_o    =  mstatus_o & 64'h80000003_000DE122;

;

//clint interrupt

    assign clint_interrupt_valid = clint_interrupt_i & csr_mstatus[3] & csr_mie[7];
    assign clint_o               = clint_interrupt_valid & if_reg_valid_i && mepc_ready == 1'b1;

    always @(posedge clk)
    begin
        if( rst == `RST )
            mepc_ready <= 1'b1;
        else if(clint_o) 
            mepc_ready <= 1'b0;
        else if(mret_i & mepc_ready == 1'b0)
            mepc_ready <= 1'b1;
        else
            mepc_ready <= mepc_ready;
    end

    always @(posedge clk) 
	begin
		if ( rst == `RST ) 
		begin
            csr_mstatus     <=    63'b0;      //{51'b0,2'b11,11'b0}; //mpp特权模式写死为11
            csr_mie         <=    `ZERO_WORD;
            csr_mtvec       <=    `ZERO_WORD; //低两位写死为00
            csr_mepc        <=    `ZERO_WORD;
            csr_mcause      <=    `ZERO_WORD;
            csr_mtval       <=    `ZERO_WORD;
            csr_mip         <=    `ZERO_WORD;
            csr_mcycle      <=    `ZERO_WORD;
            csr_minstret    <=    `ZERO_WORD;
            csr_medeleg     <=    `ZERO_WORD;
            csr_mideleg     <=    `ZERO_WORD;
            csr_mscratch    <=    `ZERO_WORD;
        end
        else if(clint_o)begin
            csr_mstatus     <=   {csr_mstatus[62:13],2'b11,csr_mstatus[10:8],mie,csr_mstatus[6:4],1'b0,csr_mstatus[2:0]};
            csr_mie         <=   csr_mie;
            csr_mtvec       <=   csr_mtvec;
            csr_mepc        <=   {if_pc_i[63:2],2'b0};
            csr_mcause      <=   64'h8000000000000007;
            csr_mtval       <=   csr_mtval;
            csr_mip         <=   csr_mip;
            csr_mcycle      <=   csr_mcycle;
            csr_minstret    <=   csr_minstret;
            csr_medeleg     <=   csr_medeleg;
            csr_mideleg     <=   csr_mideleg;
            csr_mscratch    <=   csr_mscratch;
        end
        else if(ecall_i)begin
            csr_mstatus     <=   {csr_mstatus[62:13],2'b11,csr_mstatus[10:8],mie,csr_mstatus[6:4],1'b0,csr_mstatus[2:0]};
            csr_mie         <=   csr_mie;
            csr_mtvec       <=   csr_mtvec;
            csr_mepc        <=   {pc_i[63:2],2'b0};
            csr_mcause      <=   11;
            csr_mtval       <=   csr_mtval;
            csr_mip         <=   csr_mip;
            csr_mcycle      <=   csr_mcycle;
            csr_minstret    <=   csr_minstret;
            csr_medeleg     <=   csr_medeleg;
            csr_mideleg     <=   csr_mideleg;
            csr_mscratch    <=   csr_mscratch;
        end
        else if(mret_i)begin
            csr_mstatus     <=   {csr_mstatus[62:13],2'b0,csr_mstatus[10:8],1'b1,csr_mstatus[6:4],mpie,csr_mstatus[2:0]};
            csr_mie         <=   csr_mie;
            csr_mtvec       <=   csr_mtvec;
            csr_mepc        <=   csr_mepc;
            csr_mcause      <=   csr_mcause;
            csr_mtval       <=   csr_mtval;
            csr_mip         <=   csr_mip;
            csr_mcycle      <=   csr_mcycle;
            csr_minstret    <=   csr_minstret;
            csr_medeleg     <=   csr_medeleg;
            csr_mideleg     <=   csr_mideleg;
            csr_mscratch    <=   csr_mscratch;
        end
        else if (csr_wr_ena)
            begin	
                case (csr_wr_addr) 
                    `MSTATUS  : csr_mstatus   <=   csr_wr_data[62:0];
                    `MIE      : csr_mie       <=   csr_wr_data;
                    `MTVEC    : csr_mtvec     <=   csr_wr_data;
                    `MEPC     : csr_mepc      <=   csr_wr_data;
                    `MCAUSE   : csr_mcause    <=   csr_wr_data;
                    `MTVAL    : csr_mtval     <=   csr_wr_data;
                    `MIP      : csr_mip       <=   csr_wr_data;
                    `MCYCLE   : csr_mcycle    <=   csr_wr_data;
                    `MINSTRET : csr_minstret  <=   csr_wr_data;
                    `MEDELEG  : csr_medeleg   <=   csr_wr_data;
                    `MIDELEG  : csr_mideleg   <=   csr_wr_data;
                    `MSCRATCH : csr_mscratch  <=   csr_wr_data;
                    default:
                    begin
                                csr_mstatus   <=   csr_mstatus;
                                csr_mie       <=   csr_mie;
                                csr_mtvec     <=   csr_mtvec;
                                csr_mepc      <=   csr_mepc;
                                csr_mcause    <=   csr_mcause;
                                csr_mtval     <=   csr_mtval;
                                csr_mip       <=   csr_mip;
                                csr_mcycle    <=   csr_mcycle;
                                csr_minstret  <=   csr_minstret;
                                csr_medeleg     <=   csr_medeleg;
                                csr_mideleg     <=   csr_mideleg;
                                csr_mscratch    <=   csr_mscratch;
                    end
                endcase
            end
        else
            begin
                                csr_mstatus   <=   csr_mstatus;
                                csr_mie       <=   csr_mie;
                                csr_mtvec     <=   csr_mtvec;
                                csr_mepc      <=   csr_mepc;
                                csr_mcause    <=   csr_mcause;
                                csr_mtval     <=   csr_mtval;
                                csr_mip       <=   csr_mip;
                                csr_mcycle    <=   csr_mcycle + 1'b1;
                                csr_minstret  <=   csr_minstret;
                                csr_medeleg     <=   csr_medeleg;
                                csr_mideleg     <=   csr_mideleg;
                                csr_mscratch    <=   csr_mscratch;
            end
				
		end
	
    always @(*) begin
		if (rst == `RST)
			csr_rd_data = `ZERO_WORD;
		else if (csr_rd_ena == 1'b1)
			case (csr_rd_addr) 
                `MSTATUS  : csr_rd_data   =   {sd,csr_mstatus};
                `MIE      : csr_rd_data   =   csr_mie;
                `MTVEC    : csr_rd_data   =   csr_mtvec;
                `MEPC     : csr_rd_data   =   csr_mepc;
                `MCAUSE   : csr_rd_data   =   csr_mcause;
                `MTVAL    : csr_rd_data   =   csr_mtval;
                `MIP      : csr_rd_data   =   csr_mip;
                `MCYCLE   : csr_rd_data   =   csr_mcycle;
                `MINSTRET : csr_rd_data   =   csr_minstret;
                `MEDELEG  : csr_rd_data   =   csr_medeleg;
                `MIDELEG  : csr_rd_data   =   csr_mideleg;
                `MSCRATCH : csr_rd_data   =   csr_mscratch;
                default   : csr_rd_data   =   `ZERO_WORD;
            endcase
		else
			csr_rd_data = `ZERO_WORD;
	end
      

endmodule